//Source code for 3x3 matrix 
//#include "..\Header Files\Math\Matrix3.h"
#include "Matrix3.h"

//Default constructor
Matrix3::Matrix3()
{
	m00 = m01 = m02 = m10 = m11 = m12 = m20 = m21 = m22 = 0.0f;
}

//Initialization constructor
Matrix3::Matrix3(float _m00, float _m01, float _m02,
				 float _m10, float _m11, float _m12,
				 float _m20, float _m21, float _m22)
{
	m00 = _m00; m01 = _m01; m02 = _m02;
	m10 = _m10; m11 = _m11; m12 = _m12;
	m20 = _m20; m21 = _m21; m22 = _m22;
}

//Functions

//Vector inialization of matrices

//Row vector initialization
void Matrix3::MatrixFromRow(Vector3& V0, Vector3& V1, Vector3& V2)
{
	m00 = V0.x; m01 = V0.y; m02 = V0.z;
	m10 = V1.x; m11 = V1.y; m12 = V1.z;
	m20 = V2.x; m21 = V2.y; m22 = V2.z;
}

//Column vector initialization
void Matrix3::MatrixFromCol(Vector3& V0, Vector3& V1, Vector3& V2)
{
	m00 = V0.x; m10 = V0.y; m20 = V0.z;
	m01 = V1.x; m11 = V1.y; m21 = V1.z;
	m02 = V2.x; m12 = V1.y; m22 = V2.z; 
}

//Operators on matrices

//returns a negated matrix
Matrix3 Matrix3::operator - ()
{
	return Matrix3(-m00, -m01, -m02,
				   -m10, -m11, -m12,
				   -m20, -m21, -m22);
}

//Binary operations

//addition of two matrices
Matrix3 Matrix3::operator + (Matrix3& M)
{
	return Matrix3(m00+M.m00, m01+M.m01, m02+M.m02,
				   m10+M.m10, m11+M.m11, m12+M.m12,
				   m20+M.m20, m21+M.m21, m22+M.m22);
}

//subtraction of two matrices
Matrix3 Matrix3::operator - (Matrix3& M)
{
	return Matrix3(m00-M.m00, m01-M.m01, m02-M.m02,
				   m10-M.m10, m11-M.m11, m12-M.m12,
				   m20-M.m20, m21-M.m21, m22-M.m22);
}

//Multiplication of two matrices
Matrix3 Matrix3::operator * (Matrix3& M)
{
	//we dont use a for loop
	//we write explicit code
	return Matrix3(m00*M.m00 + m01*M.m10 + m02*M.m20, m00*M.m01 + m01*M.m11 + m02*M.m21, m00*M.m02 + m01*M.m12 + m02*M.m22,
				   m10*M.m00 + m11*M.m10 + m12*M.m20, m10*M.m01 + m11*M.m11 + m12*M.m21, m10*M.m02 + m11*M.m12 + m12*M.m22,
				   m20*M.m00 + m21*M.m10 + m22*M.m20, m20*M.m01 + m21*M.m11 + m22*M.m21, m20*M.m02 + m21*M.m12 + m22*M.m22 );

}

//Multiplication with a vector
//Assuming Vector3 is a column vector
Vector3 Matrix3::operator * (Vector3& V)
{
	return Vector3(m00*V.x+m01*V.y+m02*V.z, m01*V.x+m11*V.y+m21*V.z, m02*V.x+m12*V.y+m22*V.z);
}

//Scalar division
Matrix3 Matrix3::operator / (float k)
{
	float inv_k = 1.0f/k;
	return Matrix3(inv_k*m00, inv_k*m01, inv_k*m02,
				   inv_k*m10, inv_k*m11, inv_k*m12,
				   inv_k*m20, inv_k*m21, inv_k*m22);
}

//Scalar multiplication
Matrix3 Matrix3::operator* (float k)
{
	return Matrix3(k*m00, k*m01, k*m02,
				   k*m10, k*m11, k*m12,
				   k*m20, k*m21, k*m22);
}

//Utility functions

//Get a transposed matrix from the current matrix
Matrix3 Matrix3::GetTransposedMatrix()
{
	return Matrix3(m00, m10, m20,
				   m01, m11, m21,
				   m02, m12, m22);
}

//Transpose the given matrix
void Matrix3::TransposeMatrix()
{
	float temp; 
	temp = m01; m01 = m10; m10 = temp;	//1swap
	temp = m02; m02 = m20; m20 = temp;  //2swap
	temp = m12; m12 = m21; m21 = temp;	//3swap
	//done
}

//Determinant of matrix
float Matrix3::Determinant()
{
	return m00*(m11*m22 - m12*m21) - m01*(m10*m22 - m12*m20) + m02*(m10*m21 - m11*m20);
}

//Adjacency matrix
Matrix3 Matrix3::GetAdjMatrix()
{
	//Adjugate matrix is a matrix that contains cofactors of all the elements
	return Matrix3(m11*m22-m12*m21, m20*m12-m10*m22, m10*m21-m11*m20,
			       m21*m02-m01*m22, m00*m22-m20*m02, m20*m01-m00*m21,
				   m01*m12-m02*m11, m10*m02-m00*m12, m00*m11-m10*m01);
}

//Inverse of a matrix
//For now cramers rule
//returns true if inv exists and returns the 
//else returns false
bool Matrix3::GetInverse(Matrix3& ipMatrix)
{
	float det = (m00*(m11*m22 - m12*m21) - m01*(m10*m22 - m12*m20) + m02*(m10*m21 - m11*m20));
	if(det != 0.0f)
	{
		float inv_det = 1/det;
		//only now get the invertible matrix
		ipMatrix = Matrix3(inv_det*(m11*m22-m12*m21), inv_det*(m21*m02-m01*m22), inv_det*(m01*m12-m02*m11),
						   inv_det*(m20*m12-m10*m22), inv_det*(m00*m22-m20*m02), inv_det*(m10*m02-m00*m12),
				           inv_det*(m10*m21-m11*m20), inv_det*(m20*m01-m00*m21), inv_det*(m00*m11-m10*m01));
		return true;
	}

	else return false;
}



